/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * ArrayDifference.java
 * Copyright (C) 2011 University of Waikato, Hamilton, New Zealand
 */
package adams.data.statistics;

/**
 <!-- globalinfo-start -->
 * Calculates the difference between the arrays.
 * <br><br>
 <!-- globalinfo-end -->
 *
 <!-- options-start -->
 * Valid options are: <br><br>
 *
 * <pre>-D &lt;int&gt; (property: debugLevel)
 * &nbsp;&nbsp;&nbsp;The greater the number the more additional info the scheme may output to
 * &nbsp;&nbsp;&nbsp;the console (0 = off).
 * &nbsp;&nbsp;&nbsp;default: 0
 * &nbsp;&nbsp;&nbsp;minimum: 0
 * </pre>
 *
 * <pre>-absolute (property: absoluteValue)
 * &nbsp;&nbsp;&nbsp;If set to true, then the absolute difference is returned instead.
 * </pre>
 *
 <!-- options-end -->
 *
 * @author  fracpete (fracpete at waikato dot ac dot nz)
 * @version $Revision$
 * @param <T> the data to process
 */
public class ArrayDifference<T extends Number>
  extends AbstractArrayStatistic<T>
  implements EqualLengthArrayStatistic {

  /** for serialization. */
  private static final long serialVersionUID = -5911270089583842477L;

  /** whether to return the absolute value. */
  protected boolean m_AbsoluteValue;

  /**
   * Returns a string describing the object.
   *
   * @return 			a description suitable for displaying in the gui
   */
  public String globalInfo() {
    return "Calculates the difference between the arrays.";
  }

  /**
   * Adds options to the internal list of options.
   */
  public void defineOptions() {
    super.defineOptions();

    m_OptionManager.add(
	    "absolute", "absoluteValue",
	    false);
  }

  /**
   * Sets whether to return the absolute difference.
   *
   * @param value 	if true then the absolute difference
   */
  public void setAbsoluteValue(boolean value) {
    m_AbsoluteValue = value;
    reset();
  }

  /**
   * Returns whether to return the absolute difference.
   *
   * @return 		true if the absolute difference is returned
   */
  public boolean getAbsoluteValue() {
    return m_AbsoluteValue;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return 		tip text for this property suitable for
   * 			displaying in the GUI or for listing the options.
   */
  public String absoluteValueTipText() {
    return "If set to true, then the absolute difference is returned instead.";
  }

  /**
   * Returns the length of the stored arrays.
   *
   * @return		the length of the arrays, -1 if none stored
   */
  public int getLength() {
    if (size() > 0)
      return get(0).length;
    else
      return -1;
  }

  /**
   * Returns the minimum number of arrays that need to be present.
   * -1 for unbounded.
   *
   * @return		the minimum number, -1 for unbounded
   */
  public int getMin() {
    return 2;
  }

  /**
   * Returns the maximum number of arrays that need to be present.
   * -1 for unbounded.
   *
   * @return		the maximum number, -1 for unbounded
   */
  public int getMax() {
    return -1;
  }

  /**
   * Generates the actual result.
   *
   * @return		the generated result
   */
  protected StatisticContainer doCalculate() {
    StatisticContainer<Number>	result;
    int				i;
    int				n;
    String 			prefix;
    double			diff;

    result = new StatisticContainer<Number>(getLength(), size() - 1);

    prefix = "difference";
    if (size() > 2)
      prefix += "-";

    for (i = 1; i < size(); i++) {
      if (size() > 2)
	result.setHeader(i - 1, prefix + "1-" + (i+1));
      else
	result.setHeader(i - 1, prefix);

      for (n = 0; n < getLength(); n++) {
	diff = get(0)[n].doubleValue() - get(i)[n].doubleValue();
	if (m_AbsoluteValue)
	  diff = Math.abs(diff);
	result.setCell(n, i - 1, diff);
      }
    }

    return result;
  }
}
